package uk.co.agileworks.bidpirate.service;

import java.io.IOException;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

import uk.co.agileworks.bidpirate.model.Bid;
import uk.co.agileworks.bidpirate.model.Item;
import uk.co.agileworks.bidpirate.model.User;

import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlStrong;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlTableCell;

@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.NO)
public class EbaySessionImpl implements EbaySession {

	private static final String FORM_XPATH = "//div[@id='Content']/div[last()]/form";
	private static final String STATUS_XPATH = "//div[@id='Status']//td[@class='ttext']";

	private final WebClient webClient;
	private HtmlPage currentPage;

	@Resource private String signInUrl;
	@Resource private String defaultUrl;
	@Resource private String placeBidUrl;
	@Resource private String viewItemUrl;

	private static final Logger LOGGER = LoggerFactory.getLogger(EbaySessionImpl.class);

	public EbaySessionImpl() {
		webClient = new WebClient();
		webClient.setJavaScriptEnabled(false);
		try {
			webClient.setUseInsecureSSL(true);
		} catch (GeneralSecurityException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public String confirmBid() {
		HtmlForm form = currentPage.getFirstByXPath(FORM_XPATH);
		HtmlSubmitInput submit = form.getInputByValue("Confirm");
		try {
			currentPage = (HtmlPage) submit.click();
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
		return getStatus();
	}

	@Override
	public Page getCurrentPage() {
		return currentPage;
	}

	@Override
	public boolean signedIn(User user) {
		setPage(defaultUrl);
		return getStatus().equals("Welcome " + user.getUsername() + "!");
	}

	@Override
	public void placeBid(Bid bid) {
		setPage(placeBidUrl.replaceFirst("%ITEM_NUMBER%", String.valueOf(bid.getItem()
				.getItemNumber())));
		HtmlForm form = currentPage.getFirstByXPath(FORM_XPATH);
		HtmlInput maxBid = form.getInputByName(BID_INPUT);
		maxBid.setValueAttribute(String.valueOf(bid.getMaxBid()));
		HtmlSubmitInput submit = form.getInputByValue("Next Step");
		try {
			currentPage = (HtmlPage) submit.click();
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public void signIn(User user) {

		setPage(signInUrl);
		HtmlForm form = currentPage.getFirstByXPath(FORM_XPATH);
		HtmlInput username = form.getInputByName(USERNAME_INPUT);
		HtmlInput password = form.getInputByName(PASSWORD_INPUT);
		HtmlSubmitInput submit = form.getInputByValue("Sign in");
		username.setValueAttribute(user.getUsername());
		password.setValueAttribute(user.getPassword());
		try {
			currentPage = (HtmlPage) submit.click();
			LOGGER.info("signIn: [" + currentPage.getTitleText() + "]");

		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public void signOut() {
		setPage(signInUrl);
		HtmlForm form = currentPage.getFirstByXPath(FORM_XPATH);
		HtmlSubmitInput submit = form.getInputByValue("Sign Out");
		try {
			currentPage = (HtmlPage) submit.click();
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}

	private String getStatus() {
		HtmlTableCell td = currentPage.getFirstByXPath(STATUS_XPATH);
		return td.asText();
	}

	private void setPage(String url) {
		try {
			currentPage = webClient.getPage(url);
		} catch (FailingHttpStatusCodeException e) {
			throw new IllegalStateException(e);
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException(e);
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}
	
	// TODO refactor common code - see also EbayFacadeImpl
	@Override
	public boolean won(Item item) {
		setPage(viewItemUrl.replaceFirst("%ITEM_NUMBER%", String.valueOf(item.getItemNumber())));
		HtmlStrong strong = currentPage.getFirstByXPath("//div[@id='Status']/div[3]/div/strong");
		return strong != null && "You won this item!".equals(strong.asText());
	}

}
